package javax.math;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;

import com.kinyx.framework.annotation.assist.CanNotNull;
import com.kinyx.framework.annotation.assist.CanNull;
import com.kinyx.framework.annotation.assist.Note;
import com.kinyx.framework.annotation.assist.ReturnNotNull;
import com.kinyx.framework.annotation.assist.Throws;
import com.kinyx.framework.utils.KNumberUtils;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;

/**
 * 数字对象
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class YBigDecimal {

	// ===================================================== field ===================================================== //
	/** 内置对象 */
	private BigDecimal number;
	/** 精度 */
	private Integer scale;
	/** 取整模式 */
	private RoundingMode roundingMode;

	// ===================================================== construct ===================================================== //
	/**
	 * 构造方法
	 * @param number 数值
	 * @param scale 精度
	 * @param roundingMode 取整模式
	 * @return 新对象
	 */
	@ReturnNotNull
	@Throws(at = "KNumberUtils.toBigDecimal(Object)", value = "ErrorCode0.CanNotConvertType", when = "该类型不可转换")
	public static YBigDecimal of(@CanNotNull final Object number, @CanNull(defaultValue = "roundingMode != null时默认为2") final Integer scale, @CanNull final RoundingMode roundingMode) {
		// 转换为BigDecimal
		final BigDecimal bd = KNumberUtils.toBigDecimal(number);

		final YBigDecimal that = new YBigDecimal();

		if (scale == null) {
			if (roundingMode == null) {
				that.number = bd;
			} else {
				that.roundingMode = roundingMode;
				that.number = bd.setScale(2, roundingMode);
			}
		} else {
			that.scale = scale;
			if (roundingMode == null) {
				that.number = bd.setScale(scale);
			} else {
				that.roundingMode = roundingMode;
				that.number = bd.setScale(scale, roundingMode);
			}
		}

		return that;
	}

	/**
	 * 构造方法
	 * @param number 数值
	 * @return 新对象
	 */
	@ReturnNotNull
	@Throws(at = "KNumberUtils.toBigDecimal(Object)", value = "ErrorCode0.CanNotConvertType", when = "该类型不可转换")
	public static YBigDecimal of(@CanNotNull final Object number) {
		return of(number, null, null);
	}

	// ===================================================== clone ===================================================== //
	/**
	 * 克隆
	 * @return 新对象
	 */
	@ReturnNotNull
	@Throws(at = "KNumberUtils.toBigDecimal(Object)", value = "ErrorCode0.CanNotConvertType", when = "该类型不可转换")
	public YBigDecimal cloneX() {
		return of(this.number, this.scale, this.roundingMode);
	}

	// ===================================================== calculate ===================================================== //
	/**
	 * 加法
	 * @param number 数值
	 * @return 本对象
	 */
	@ReturnNotNull
	@Note("return this;")
	@Throws(at = "KNumberUtils.toBigDecimal(Object)", value = "ErrorCode0.CanNotConvertType", when = "该类型不可转换")
	public YBigDecimal add(@CanNotNull final Object number) {
		this.number = this.number.add(KNumberUtils.toBigDecimal(number));
		return this;
	}

	/**
	 * 减法
	 * @param number 数值
	 * @return 本对象
	 */
	@ReturnNotNull
	@Note("return this;")
	@Throws(at = "KNumberUtils.toBigDecimal(Object)", value = "ErrorCode0.CanNotConvertType", when = "该类型不可转换")
	public YBigDecimal subtract(@CanNotNull final Object number) {
		this.number = this.number.subtract(KNumberUtils.toBigDecimal(number));
		return this;
	}

	/**
	 * 乘法
	 * @param number 数值
	 * @return 本对象
	 */
	@ReturnNotNull
	@Note("return this;")
	@Throws(at = "KNumberUtils.toBigDecimal(Object)", value = "ErrorCode0.CanNotConvertType", when = "该类型不可转换")
	public YBigDecimal multiply(@CanNotNull final Object number) {
		this.number = this.number.multiply(KNumberUtils.toBigDecimal(number));
		return this;
	}

	/**
	 * 除法
	 * @param number 数值
	 * @return 本对象
	 */
	@ReturnNotNull
	@Note("return this;")
	@Throws(at = "KNumberUtils.toBigDecimal(Object)", value = "ErrorCode0.CanNotConvertType", when = "该类型不可转换")
	public YBigDecimal divide(@CanNotNull final Object number) {
		if (this.scale == null) {
			if (this.roundingMode == null) {
				this.number = this.number.divide(KNumberUtils.toBigDecimal(number), MathContext.DECIMAL128);
			} else {
				this.number = this.number.divide(KNumberUtils.toBigDecimal(number), this.roundingMode);
			}
		} else {
			if (this.roundingMode == null) {
				this.number = this.number.divide(KNumberUtils.toBigDecimal(number), this.scale, RoundingMode.HALF_UP);
			} else {
				this.number = this.number.divide(KNumberUtils.toBigDecimal(number), this.scale, this.roundingMode);
			}
		}
		return this;
	}

	/**
	 * 取反
	 * @return 本对象
	 */
	@ReturnNotNull
	@Note("return this;")
	public YBigDecimal negate() {
		this.number = this.number.negate();
		return this;
	}

	/**
	 * 取绝对值
	 * @return 本对象
	 */
	@ReturnNotNull
	@Note("return this;")
	public YBigDecimal abs() {
		this.number = this.number.abs();
		return this;
	}

	// ===================================================== compare ===================================================== //
	/**
	 * 比较大小
	 * @param number 数值
	 * @return -1: 小于; 0: 等于; 1: 大于;
	 */
	@Note("-1: 小于; 0: 等于; 1: 大于;")
	@Throws(at = "KNumberUtils.toBigDecimal(Object)", value = "ErrorCode0.CanNotConvertType", when = "该类型不可转换")
	@ReturnNotNull
	public int compareTo(@CanNotNull final Object number) {
		return this.number.compareTo(KNumberUtils.toBigDecimal(number));
	}

	/**
	 * 判断是否大于数值
	 * @param number 数值
	 * @return true：大于；false：小于或等于；
	 */
	@Throws(at = "KNumberUtils.toBigDecimal(Object)", value = "ErrorCode0.CanNotConvertType", when = "该类型不可转换")
	@ReturnNotNull
	public boolean moreThan(@CanNotNull final Object number) {
		return this.compareTo(number) == 1;
	}

	/**
	 * 判断是否等于数值
	 * @param number 数值
	 * @return true：等于；false：大于或小于；
	 */
	@Throws(at = "KNumberUtils.toBigDecimal(Object)", value = "ErrorCode0.CanNotConvertType", when = "该类型不可转换")
	@ReturnNotNull
	public boolean equalTo(@CanNotNull final Object number) {
		return this.compareTo(number) == 0;
	}

	/**
	 * 判断是否小于数值
	 * @param number 数值
	 * @return true：小于；false：大于或等于；
	 */
	@Throws(at = "KNumberUtils.toBigDecimal(Object)", value = "ErrorCode0.CanNotConvertType", when = "该类型不可转换")
	@ReturnNotNull
	public boolean lessThan(@CanNotNull final Object number) {
		return this.compareTo(number) == -1;
	}

	// ===================================================== value ===================================================== //
	/** @return 取byte值 */
	@ReturnNotNull
	public byte byteValue() { return this.number.byteValue(); }

	/** @return 取short值 */
	@ReturnNotNull
	public short shortValue() { return this.number.shortValue(); }

	/** @return 取int值 */
	@ReturnNotNull
	public int intValue() { return this.number.intValue(); }

	/** @return 取long值 */
	@ReturnNotNull
	public long longValue() { return this.number.longValue(); }

	/** @return 取float值 */
	@ReturnNotNull
	public float floatValue() { return this.number.floatValue(); }

	/** @return 取double值 */
	@ReturnNotNull
	public double doubleValue() { return this.number.doubleValue(); }

	/** @return 取BigDecimal值 */
	@ReturnNotNull
	public BigDecimal bigDecimalValue() { return this.number; }

	/** @return 取String值 */
	@ReturnNotNull
	public String stringValue() { return this.toString(); }

	// ===================================================== Override ===================================================== //
	@Override
	public String toString() { return this.number.toString(); }

}
